/************************************************************************
	 * AIDE - Automata Identification Engine
	 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
	 * **********************************************************************
	 * This program is free software; you can redistribute it and/or modify it
	 * under the terms of the GNU Lesser General Public License (LGPL) published 
	 * by the Free Software Foundation; either version 2.1 of the License, or (at your
	 * option) any later version. This program is distributed without any
	 * warranty. See the GNU Lesser General Public License for more details.
	 * ***********************************************************************
	 * File         :     AIDE\Filters\NFMs\NFM_LearningPurpose.cs
	 * Description  :     Providing the learning purpose for NFMs
	 * Change log   :     
	 ************************************************************************/
using System;
using SMLib.Automata.MM;
using SMLib.Automata.Base;

namespace AIDE.Filters.NFMs
{
	/// <summary>
	/// Learning purpose for NFMs and Mealy machines
	/// </summary>
	public class Filter_MM_LearningPurpose: IBlackBox_MM
	{
		MealyMachine learningPurpose;
		IBlackBox_MM SUL;
		MealyMachine.Mealy_State currentState;

		/// <summary>
		/// Initializes a new instance of the <see cref="AIDE.Filters.NFMs.Filter_MM_LearningPurpose"/> class.
		/// </summary>
		/// <param name='learningPurpose'>
		/// Learning purpose.
		/// </param>
		/// <param name='SUL'>
		/// The SUL
		/// </param>
		public Filter_MM_LearningPurpose (MealyMachine learningPurpose, IBlackBox_MM SUL)
		{
			this.learningPurpose = learningPurpose;
			this.SUL = SUL;
		}

		/// <summary>
		/// Checks the conditions.
		/// </summary>
		/// <returns>
		/// True if the machine was OK as a "filter", false in other case
		/// </returns>
		public bool CheckConditions ()
		{
			return true;
		}

		#region IBlackBox_MealyMachine implementation
		public void Reset ()
		{
			currentState = learningPurpose.InitialState;
			SUL.Reset ();
		}

		public ISymbol Step (ISymbol input)
		{
			bool enabled = false;
			bool inputExpl = false;
				
			//* check that the action is enabled or not?
			for (int i=0; i<currentState.Transitions.Count; i++) {
				ISymbol s = currentState.Transitions [i].inLabel;
					
				if (s.Equals (input) || s.Equals ("*")) {
					enabled = true;
					break;
				}
			}

			//* if enabled?
			if (enabled) {
				//* now, check what is the output?
				ISymbol o = SUL.Step (input);
					
				for (int i=0; i<currentState.Transitions.Count; i++) {
					ISymbol s = currentState.Transitions [i].inLabel;
						
					if (s.Equals (input)) {
						inputExpl = true;
						break;
					}
				}

				//* 1-if input is given explicitely
				if (inputExpl) {
					for (int i=0; i<currentState.Transitions.Count; i++) {
						ISymbol s = currentState.Transitions [i].inLabel;
						ISymbol o2 = currentState.Transitions [i].outLabel;
							
						//* also the output matches							
						if (s.Equals (input) && o.Equals (o2)) {
							currentState = currentState.Transitions [i].Destination;
							return o;							
						}
					}
					//* no output matched!
					for (int i=0; i<currentState.Transitions.Count; i++) {
						ISymbol s = currentState.Transitions [i].inLabel;
						ISymbol o2 = currentState.Transitions [i].outLabel;
							
						if (s.Equals (input) && o2.Equals ("*")) {
							currentState = currentState.Transitions [i].Destination;
							return o;
						}						
					}
					//* NEVER HAPPENS!
					return null;
				}
					//* 2-the input is not given explicitly!
					else {
					for (int i=0; i<currentState.Transitions.Count; i++) {
						ISymbol s = currentState.Transitions [i].inLabel;
						ISymbol o2 = currentState.Transitions [i].outLabel;
							
						//* but the output matches							
						if (s.Equals ("*") && o.Equals (o2)) {
							currentState = currentState.Transitions [i].Destination;
							return o;							
						}
					}
					//* also no output matched!
					for (int i=0; i<currentState.Transitions.Count; i++) {
						ISymbol s = currentState.Transitions [i].inLabel;
						ISymbol o2 = currentState.Transitions [i].outLabel;
							
						if (s.Equals ("*") && o2.Equals ("*")) {
							currentState = currentState.Transitions [i].Destination;
							return o;
						}						
					}
					//* NEVER HAPPENS!
					return null;
				}
			} else
					//throw new NotEnabledActionException("");
				return null;
		}

		public Alphabet InputAlphabet {
			get {
				return SUL.InputAlphabet;
			}
		}
		#endregion
	}
}
	
